<?php
/**
 * A simple description for this script
 *
 * PHP Version 5.2.4 or Upper version
 *
 * @package    WhiteoutResuce
 * @author     Hidehito NOZAWA aka Suin <http://suin.asia/>
 * @copyright  2010 Hidehito NOZAWA
 * @license    http://www.gnu.org/licenses/gpl-2.0.html GNU GPL v2 or later
 *
 */

if ( !defined('XOOPS_ROOT_PATH') ) exit;

error_reporting(E_ALL);
define('OH_MY_GOD_HELP_ME', true);

declare(ticks=1);
ob_start();
register_shutdown_function(array('WhiteoutRescueMain', 'shutdown'));
register_tick_function(array('WhiteoutRescueMain', 'tick'));

class WhiteoutRescueMain
{
	public static $scriptStats = array();
	public static $time        = 0;
	public static $ticks       = 0;

	public static function shutdown()
	{
		$contents = '';

		while ( $content = @ob_get_contents() )
		{
			$contents .= $content;
			ob_end_clean();
		}

		if ( $contents )
		{
			echo $contents;
			return;
		}

		$error = error_get_last();
		$criticalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR);
		$lastError = null;

		if ( is_array($error) )
		{
			if ( isset($error['type']) and in_array($error['type'], $criticalErrors) )
			{
				$lastError = $error;
			}
		}

		self::$scriptStats = self::_castObjectToString(self::$scriptStats);

		$headers = headers_list();
		$includedFiles = get_included_files();
		$queries = self::_getSqlLog();

		?>
		<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
		<html xmlns="http://www.w3.org/1999/xhtml"> 
		<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
		<title>ホワイトアウトレスキュー</title>
		<style>
		body {
			background: #111111;
			color: #ffffff;
		}
		h1, h2, h3 {
			color: #3fcd52;
		}
		em {
			color: #3fcd52;
		}
		table {
			border: 1px white solid;
			border-collapse: collapse;
		}
		td, th {
			border: 1px white solid;
			padding: 5px;
		}
		</style>
		</head>
		<body>
		<h1>ホワイトアウトレスキュー</h1>
		<p>セキュリティ上、このプリロードが不要のときは削除するようにしてください。</p>
		<h2>エラーメッセージ</h2>
		<?php if ( is_array($lastError) ) : ?>
		<table>
		<tr>
		<th>ファイル</th><td><?php echo self::_escape($lastError['file']); ?></td>
		</tr>
		<tr>
		<th>行</th><td><?php echo self::_escape($lastError['line']); ?></td>
		</tr>
		<tr>
		<th>メッセージ</th><td><?php echo self::_escape($lastError['message']); ?></td>
		</tr>
		</table>
		<?php else : ?>
		<p>致命的なエラーで終了したのではなさそうです。</p>
		<?php endif ?>
		
		<h2>処理中断</h2>
		<p>エラーメッセージが出ずに、この画面が表示された場合、exit(); die();などで処理が中断された可能性が高いです。処理が中断した場所は以下の数行あとかもしれません。</p>
		<table>
		<tr>
		<th>ファイル</th><td><?php echo self::_escape(self::$scriptStats['trace']['file']); ?></td>
		</tr>
		<tr>
		<th>行</th><td><?php echo self::_escape(self::$scriptStats['trace']['line']); ?></td>
		</tr>
		</table>
		<h2>送信済みヘッダ</h2>
		<ul>
		<?php foreach ( $headers as $header ) :?>
		<li><?php echo self::_escape($header); ?></li>
		<?php endforeach ?>
		</ul>
		<h2>送信されたクエリー</h2>
		<?php if ( is_array($queries) ) : ?>
		<ul>
		<?php foreach ( $queries as $query ) : ?>
		<?php if ( $query['error'] ) : ?>
		<li>
		<?php echo self::_escape($query['query']); ?><br />
		<em><?php echo self::_escape($query['error_message']); ?></em>
		</li>
		<?php else : ?>
		<li><?php echo self::_escape($query['query']); ?></li>
		<?php endif ?>
		<?php endforeach ?>
		</ul>
		<?php else : ?>
		<p>送信されたクエリーはありません。</p>
		<?php endif ?>
		<h2>読み込まれたファイル</h2>
		<ul>
		<?php foreach ( $includedFiles as $file ) :?>
		<li><?php echo self::_escape($file); ?></li>
		<?php endforeach ?>
		</ul>
		
		</body>
		</html>
		<?php
	}

	public static function tick()
	{
		$trace = debug_backtrace();
		$exeTime = (microtime(true) - self::$time) * 1000;

		self::$scriptStats = array(
			'current_time' => microtime(true),
			'memory'       => memory_get_usage(true),
			'trace'        => $trace[1],
			'ns'           => $exeTime,
		);

		self::$time = microtime(true);
		self::$ticks++;
	}

	protected static function _castObjectToString($object)
	{
		if ( is_array($object) )
		{
			foreach ( $object as $k => $value )
			{
				$object[$k] = self::_castObjectToString($value);
			}
		}
		elseif ( is_object($object) )
		{
			return get_class($object);
		}

		return $object;
	}

	protected static function _escape($string)
	{
		$string = str_replace(XOOPS_ROOT_PATH, 'xoops_root', $string);

		if ( defined('XOOPS_TRUST_PATH') )
		{
			$string = str_replace(XOOPS_TRUST_PATH, 'xoops_trust', $string);
		}

		return htmlspecialchars($string, ENT_QUOTES);
	}


	protected static function _getSqlLog()
	{
		if ( !class_exists('XoopsLogger') )
		{
			return false;
		}

		$xoopsLogger =& XoopsLogger::instance();
		$log = array();

		foreach( $xoopsLogger->queries as $query )
		{
			$log[] = array(
				'error' => ( $query['errno'] > 0 ),
				'query' => str_replace(XOOPS_DB_PREFIX.'_', '{prefix}_', $query['sql']),
				'error_no' => $query['errno'],
				'error_message' => $query['error'],
			);
		}

		return $log;
	}
}

?>